package de.rj.urwalking.ui.activities;

import java.util.ArrayList;

import android.content.Intent;
import android.hardware.SensorEvent;
import android.location.Location;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.content.Loader;
import android.text.Html;
import android.util.Log;
import android.widget.Toast;

import com.actionbarsherlock.app.ActionBar;
import com.actionbarsherlock.app.ActionBar.OnNavigationListener;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
import com.google.android.gms.maps.model.LatLng;

import de.rj.urwalking.R;
import de.rj.urwalking.config.Constants;
import de.rj.urwalking.data.Perspective;
import de.rj.urwalking.interfaces.ControllableFragment;
import de.rj.urwalking.loader.RouteLoader;
import de.rj.urwalking.ui.fragments.JpctFragment;
import de.rj.urwalking.ui.fragments.OutdoorFragment;
import de.rj.urwalking.ui.fragments.UrwGoogleMapFragment;
import de.rj.urwalking.util.ExperimentManager;
import de.rj.urwalking.util.PerspectiveAdapter;
import de.rose_mobil.models.route.Route;

public class HybridActivity extends URwalkingActivity implements OnNavigationListener {

	private Fragment mFragment;
	private int mPerspective;
	private PerspectiveAdapter mPerspectiveAdapter;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_outdoor);

		initUI();
		initSensors();
	}

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);

		switch (requestCode) {
		case Constants.QUESTIONS_ACTIVITY_REQUEST_CODE:
			// if the survey wasn't finished, there won't be any data
			if (data == null) return;

			// if it was finished, remember the name of the object
			Bundle extras = data.getExtras();
			if (extras == null) return;
			String name = extras.getString("name");
			if (mFragment instanceof ControllableFragment) {
				((ControllableFragment) mFragment).setObjectName(name);
			}

			break;
		}
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		super.onCreateOptionsMenu(menu);
		getSupportMenuInflater().inflate(R.menu.hybrid_menu, menu);

		return true;
	}

	@Override
	public boolean onPrepareOptionsMenu(Menu menu) {

		// set the state of the experiment control menu item
		MenuItem item = menu.findItem(R.id.menu_experiment);

		if (ExperimentManager.getInstance().isExperimentRunning()) {
			item.setTitle(getString(R.string.stop_experiment));
			item.setIcon(R.drawable.av_stop);
		} else {
			item.setTitle(getString(R.string.start_experiment));
			item.setIcon(R.drawable.av_play);
		}

		// set the state of the compass menu item
		item = menu.findItem(R.id.menu_compass);

		if (useCompass && mCompassIsAccurate) {
			item.setIcon(R.drawable.ic_menu_compass_active);
		} else if (useCompass && !mCompassIsAccurate) {
			item.setIcon(R.drawable.ic_menu_compass_inaccurate);
		} else {
			item.setIcon(R.drawable.ic_menu_compass);
		}

		// set the state of the gps menu item
		item = menu.findItem(R.id.urwalking_menu_gps);

		if (followGPS) {
			item.setIcon(R.drawable.ic_menu_mylocation_active);
		} else {
			item.setIcon(R.drawable.ic_menu_mylocation);
		}

		return super.onPrepareOptionsMenu(menu);
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case R.id.menu_experiment:
			if (ExperimentManager.getInstance().isExperimentRunning()) {
				Log.i(TAG, HybridActivity.class.getName() + " Experiment still running.");
				finishExperiment(true, false);
			} else {
				Log.i(TAG, HybridActivity.class.getName() + " Try to start new experiment.");
				startExperiment();
			}
			break;
		case R.id.menu_compass:
			toggleCompass();
			ActivityCompat.invalidateOptionsMenu(this);
			break;
		case R.id.urwalking_menu_gps:
			toggleGPS();
			break;
		default:
			return super.onOptionsItemSelected(item);
		}
		return true;
	}

	@Override
	protected void initUI() {
		super.initUI();

		showGMap();
		mPerspective = Perspective.TYPE_MAP;

		// TODO: maybe populate this arraylist somewhere else statically?
		ArrayList<Integer> perspectives = new ArrayList<Integer>();
		perspectives.add(Perspective.TYPE_MAP);
		perspectives.add(Perspective.TYPE_SATELLITE);
		perspectives.add(Perspective.TYPE_3D_STREET);
		perspectives.add(Perspective.TYPE_3D_ABOVE);

		mPerspectiveAdapter = new PerspectiveAdapter(getSupportActionBar().getThemedContext(), perspectives);
		
		getSupportActionBar().setDisplayShowTitleEnabled(false);
		getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
		getSupportActionBar().setListNavigationCallbacks(mPerspectiveAdapter, this);

	}

	private void showGMap() {

		mFragment = new UrwGoogleMapFragment();
		Bundle args = new Bundle();
		mFragment.setArguments(args);

		FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
		ft.replace(R.id.fragment_container, mFragment);
		ft.commit();
	}

	@Override
	public void onLocationChanged(Location location) {

		if (!followGPS) return;

		mLocation = location;
		if (mFragment instanceof ControllableFragment) {
			((ControllableFragment) mFragment).setLocation(mLocation);
		}
	}

	@Override
	public void onConnected(Bundle arg0) {
		super.onConnected(arg0);

		if (followGPS) {
			mLocation = mLocationClient.getLastLocation();

			if (mFragment instanceof ControllableFragment) {
				((ControllableFragment) mFragment).setLocation(mLocation);
			}
		}
	}

	@Override
	public void onSensorChanged(SensorEvent event) {
		super.onSensorChanged(event);

		if (!useCompass) return;

		if (mFragment instanceof ControllableFragment) {
			((ControllableFragment) mFragment).setOrientation(mOrientationZ);
		}
	}

	protected void changePerspective(int perspective) {

		// do nothing if same perspective chosen as we're already in
		if (perspective == mPerspective) return;

		mPerspective = perspective;

		switch (perspective) {
		case Perspective.TYPE_SATELLITE:
		case Perspective.TYPE_MAP:
			if (mFragment instanceof UrwGoogleMapFragment) {
				// if the google map is already shown, we just need to change the map type
				((UrwGoogleMapFragment) mFragment).setMapType(perspective);
			} else {
				// otherwise, we have to switch the fragments and show the 3d view
				switchFragments(); // TODO: tell fragment which perspective to use
			}
			break;
		case Perspective.TYPE_3D_ABOVE:
		case Perspective.TYPE_3D_STREET:
			if (mFragment instanceof OutdoorFragment) {
				// if the 3d view is already shown, we just need to change the camera perspective
				((OutdoorFragment) mFragment).setPerspective(perspective);
			} else {
				// otherwise, we have to switch the fragments and show the google map
				switchFragments();
			}
		}

	}

	private void switchFragments() {

		if (mFragment instanceof UrwGoogleMapFragment) {
			JpctFragment fragment = new OutdoorFragment();
			Bundle args = new Bundle();
			args.putDouble("cameraLat", mLocation.getLatitude());
			args.putDouble("cameraLon", mLocation.getLongitude());
			args.putInt("perspective", mPerspective);
			fragment.setArguments(args);

			switchFragments(fragment);
		} else if (mFragment instanceof OutdoorFragment) {

			UrwGoogleMapFragment fragment = new UrwGoogleMapFragment();
			Bundle args = new Bundle();
			args.putDouble("cameraLat", mLocation.getLatitude());
			args.putDouble("cameraLon", mLocation.getLongitude());
			args.putInt("perspective", mPerspective);
			fragment.setArguments(args);
			switchFragments(fragment);

		}
	}

	@Override
	public void switchFragments(Fragment fragment) {
		mFragment = fragment;

		if (fragment.getArguments().getInt("perspective") != 0) {
			mPerspective = fragment.getArguments().getInt("perspective");
			ActivityCompat.invalidateOptionsMenu(this);
			getSupportActionBar().setSelectedNavigationItem(mPerspectiveAdapter.getPosition(mPerspective));
		}

		FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
		ft.setCustomAnimations(R.anim.fragment_fade_in_zoom_out, R.anim.fragment_fade_out_zoom_in);
		ft.replace(R.id.fragment_container, fragment);
		ft.commit();

	}

	@Override
	public Loader<Route> onCreateLoader(int id, Bundle args) {

		double startLat = args.getDouble("startLat");
		double startLon = args.getDouble("startLon");
		double destinationLat = args.getDouble("destinationLat");
		double destinationLon = args.getDouble("destinationLon");
		return new RouteLoader(this, new LatLng(startLat, startLon), new LatLng(destinationLat, destinationLon));
	}

	@Override
	public void onLoadFinished(Loader<Route> loader, Route route) {

		mRoute = route;
		((ControllableFragment) mFragment).setRoute(route);

		// parse embedded HTML tags and show first instruction
		String firstInstruction = mRoute.getRouteParts()[0].getExtraData().get(0);
		mDirectionsTextView.setText(Html.fromHtml(firstInstruction));

	}

	@Override
	public void onLoaderReset(Loader<Route> loader) {
		// TODO Auto-generated method stub

	}

	@Override
	public boolean onNavigationItemSelected(int itemPosition, long itemId) {

		// check which perspective was chosen
		int perspective = (Integer) mPerspectiveAdapter.getItem(itemPosition);

		changePerspective(perspective);

		return false;
	}

}
